package com.ho1ho.audioexample.utils.others;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;

/**
 * Author: Michael Leo
 * Date: 19-8-30 下午4:20
 */
public class ByteUtil {

    private static ByteBuffer buffer = ByteBuffer.allocate(8);

    public static byte int2Byte(int x) {
        return (byte) x;
    }

    public static byte[] byte2Bytes(byte b) {
        return new byte[]{b};
    }

    /**
     * Force convert int value in byte array.
     *
     * @param val The val will be converted to byte.
     * @return The byte array.
     */
    public static byte[] intAsByteAndForceToBytes(int val) {
        return byte2Bytes(int2Byte(val));
    }

    public static int byte2Int(byte b) {
        return b & 0xFF;
    }

    public static int bytes2Int(byte[] b) {
        return b[3] & 0xFF |
                (b[2] & 0xFF) << 8 |
                (b[1] & 0xFF) << 16 |
                (b[0] & 0xFF) << 24;
    }

    public static int bytes2IntLE(byte[] b) {
        return (b[3] & 0xFF) << 24 |
                (b[2] & 0xFF) << 16 |
                (b[1] & 0xFF) << 8 |
                (b[0] & 0xFF) << 0;
    }

    public static int bytes2Int(byte[] b, int index) {
        return b[index + 3] & 0xFF |
                (b[index + 2] & 0xFF) << 8 |
                (b[index + 1] & 0xFF) << 16 |
                (b[index + 0] & 0xFF) << 24;
    }

    public static int bytes2IntLE(byte[] b, int index) {
        return b[index] & 0xFF |
                (b[index + 1] & 0xFF) << 8 |
                (b[index + 2] & 0xFF) << 16 |
                (b[index + 3] & 0xFF) << 24;
    }

    public static byte[] int2Bytes(int a) {
        return new byte[]{
                (byte) ((a >> 24) & 0xFF),
                (byte) ((a >> 16) & 0xFF),
                (byte) ((a >> 8) & 0xFF),
                (byte) (a & 0xFF)
        };
    }

    public static byte[] intLE2Bytes(int a) {
        return new byte[]{
                (byte) ((a >> 0) & 0xFF),
                (byte) ((a >> 8) & 0xFF),
                (byte) ((a >> 16) & 0xFF),
                (byte) ((a >> 24) & 0xFF)
        };
    }

    public static void bytes2Short(byte[] b, short s, int index) {
        b[index + 1] = (byte) (s >> 8);
        b[index + 0] = (byte) (s >> 0);
    }

    public static void bytes2ShortLE(byte[] b, short s, int index) {
        b[index + 0] = (byte) (s >> 8);
        b[index + 1] = (byte) (s >> 0);
    }

    public static short bytes2Short(byte[] b, int index) {
        return (short) (((b[index + 0] << 8) | b[index + 1] & 0xff));
    }

    public static short bytes2ShortLE(byte[] b, int index) {
        return (short) (((b[index + 1] << 8) | b[index + 0] & 0xff));
    }

    public static byte[] short2Bytes(short s) {
        byte[] targets = new byte[2];
        for (int i = 0; i < 2; i++) {
            int offset = (targets.length - 1 - i) * 8;
            targets[i] = (byte) ((s >>> offset) & 0xff);
        }
        return targets;
    }

    public static byte[] shortLE2Bytes(short s) {
        byte[] targets = new byte[2];
        for (int i = 0; i < 2; i++) {
            targets[i] = (byte) ((s >>> i * 8) & 0xff);
        }
        return targets;
    }

    public static short bytes2Short(byte[] b) {
        return bytes2Short(b, 0);
    }

    public static short bytes2ShortLE(byte[] b) {
        return bytes2ShortLE(b, 0);
    }

    public static byte[] long2Bytes(long x) {
        buffer.putLong(0, x);
        return buffer.array();
    }

    public static long bytes2Long(byte[] bytes) {
        buffer.put(bytes, 0, bytes.length);
        buffer.flip();//need flip
        return buffer.getLong();
    }

    public static byte[] getBytes(byte[] data, int start, int end) {
        byte[] ret = new byte[end - start];
        for (int i = 0; (start + i) < end; i++) {
            ret[i] = data[start + i];
        }
        return ret;
    }

    public static byte[] readInputStream(InputStream inStream) {
        ByteArrayOutputStream outStream = null;
        try {
            outStream = new ByteArrayOutputStream();
            byte[] buffer = new byte[1024];
            byte[] data = null;
            int len = 0;
            while ((len = inStream.read(buffer)) != -1) {
                outStream.write(buffer, 0, len);
            }
            data = outStream.toByteArray();
            return data;
        } catch (IOException e) {
            return null;
        } finally {
            try {
                if (outStream != null) {
                    outStream.close();
                }
                if (inStream != null) {
                    inStream.close();
                }
            } catch (IOException e) {
                return null;
            }
        }
    }

    public static InputStream readByteArr(byte[] b) {
        return new ByteArrayInputStream(b);
    }


    public static boolean isEqual(byte[] s1, byte[] s2) {
        int slen = s1.length;
        if (slen == s2.length) {
            for (int index = 0; index < slen; index++) {
                if (s1[index] != s2[index]) {
                    return false;
                }
            }
            return true;
        }
        return false;
    }

    public static String getString(byte[] s1, String encode, String err) {
        try {
            return new String(s1, encode);
        } catch (UnsupportedEncodingException e) {
            return err;
        }
    }

    public static String getString(byte[] s1, String encode) {
        return getString(s1, encode, null);
    }

    public static String bytes2HexString(byte[] b) {
        String result = "";
        for (int i = 0; i < b.length; i++) {
            result += Integer.toString((b[i] & 0xff) + 0x100, 16).substring(1);
        }
        return result;
    }

    public static int hexString2Int(String hexString) {
        return Integer.parseInt(hexString, 16);
    }

    public static String int2Binary(int i) {
        return Integer.toBinaryString(i);
    }

//    public static byte[] mergeBytes(byte[] b1, byte[] b2) {
//        byte[] b3 = new byte[b1.length + b2.length];
//        System.arraycopy(b1, 0, b3, 0, b1.length);
//        System.arraycopy(b2, 0, b3, b1.length, b2.length);
//        return b3;
//    }

    public static byte[] mergeByte(byte... bs) {
        byte[] result = new byte[bs.length];
        System.arraycopy(bs, 0, result, 0, result.length);
        return result;
    }

    public static byte[] mergeBytes(byte[]... byteList) {
        int lengthByte = 0;
        for (byte[] bytes : byteList) {
            lengthByte += bytes.length;
        }
        byte[] allBytes = new byte[lengthByte];
        int countLength = 0;
        for (byte[] b : byteList) {
            System.arraycopy(b, 0, allBytes, countLength, b.length);
            countLength += b.length;
        }
        return allBytes;
    }

    public static void main(String[] args) {
        System.err.println(isEqual(new byte[]{1, 2}, new byte[]{1, 2}));
        System.err.println(bytes2HexString(new byte[]{0, 0, 1, 0}));
        System.err.println(bytes2Int(new byte[]{0, 0, 1, 0}));
        System.err.println(bytes2IntLE(new byte[]{0, 0, 1, 0}));
//        System.err.println(JsonUtil.toHexadecimalString(int2Bytes(6867)));
//        System.err.println(JsonUtil.toHexadecimalString(intLE2Bytes(6867)));
    }
}
